package de.zefania.api.impl;


import java.io.File;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import de.zefania.api.BibleBook;
import de.zefania.api.BibleModul;
import de.zefania.api.ModulInformation;
import de.zefania.api.Position;

/**
 * this class enables access to a zefania xml modul
 * @author Thomas
 *
 */
public class ModulImpl implements BibleModul{
	private File file;
	private String digest;	
	private int[] books;
	private String revision;
	private ModulInformation information;
	private CaptionImpl[] captions;
	private JfaniaCache cache;
	private Logger logger = Logger.getLogger(ModulImpl.class);
		
	/** 
	 * creates a bible modul object by a given File handle and a ModulReader Object 
	 * @param file
	 * @param mr
	 */
	public ModulImpl(final File file, final String cachePath) {
		BasicConfigurator.configure(); 
		
		logger.setLevel(Level.TRACE);
		this.file = file;
		
		try {
			this.digest = Utilities.getDigest(file, "MD5");
			Document doc = XmlTools.getDocumentFromFile(file);
			this.information = new BibleInformationImpl(readInformation(doc),this.digest);
			this.books = readBooklist(doc);
			this.captions = readCaptions(doc);
			this.cache = new JfaniaCache(this.file,this.digest,cachePath);			
		} catch (NoSuchAlgorithmException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (JfaniaException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}	
	@Override
	public final String getDigest() { return this.digest; }	
	@Override
	public final CaptionImpl[] getCaptions() { return captions; }
	@Override
	public final String getRevision() { return revision; }
	@Override
	public final ModulInformation getInformation() { return this.information; }
	
	@Override
	public final Document getBibleText(final Position pos) {
		Document docF = null;
		if (pos.b1()==pos.b2()) {
			if (pos.c1()==pos.c2()) {
				docF = getSection(pos.b1(), pos.c1(), pos.v1(), pos.v2());				
			} else {
				//TODO multi chapter span
			}			
		} else {
			//TODO multi book span not available
		}
		
		
		return docF;	
	}

	@Override
	public final ChapterImpl getChapter(final int bnumber, final int cnumber) {
		return new ChapterImpl(new PositionImpl(bnumber,cnumber,0),cache.getChapter(bnumber, cnumber));
	}
	
	private Document getSection(final int b, final int c, final int v1, final int v2) {
		return cache.getSection(b, c, v1, v2);		
	}
	
	private HashMap<String, String[]> readInformation(final Document doc) 
			throws SAXException, IOException, ParserConfigurationException {
		NodeList infoNodes = doc.getElementsByTagName("INFORMATION").item(0).getChildNodes();
		HashMap<String,String[]> infoMap = new HashMap<String,String[]>();
		for (int i=0;i<infoNodes.getLength();i++) {	
			Node currentNode = infoNodes.item(i);
			String key = currentNode.getNodeName();
			logger.trace("Reading information: "+key);
			if (currentNode.getNodeType()==Node.ELEMENT_NODE) {
				String[] newData;
				if (infoMap.containsKey(key)) {
					String[] oldData = infoMap.get(key);
					newData = new String[oldData.length+1];
					for (int n=0;n<oldData.length;n++) {
						newData[n] = oldData[n];
					}
					newData[newData.length-1] = currentNode.getTextContent();
					
					//List<String> list = Arrays.asList(infoMap.get(key));
					
					//list.add(currentNode.getTextContent());
					//newData = list.toArray(newData);										
				} else {
					newData = new String[1];
					newData[0] =  currentNode.getTextContent();					
				}
				infoMap.put(currentNode.getNodeName(),newData);			
			}
		}
		return infoMap;		
	}
	
	private CaptionImpl[] readCaptions(final Document doc) 
			throws SAXException, IOException, ParserConfigurationException {
		NodeList nodes = doc.getElementsByTagName("CAPTION");
		CaptionImpl[] captionList = new CaptionImpl[nodes.getLength()];
		for (int i=0;i<nodes.getLength();i++) {
			Node n = nodes.item(i);
			String text = n.getTextContent();
			int vnumber = Integer.parseInt(n.getAttributes().getNamedItem("vref").getNodeValue());
			int cnumber = Integer.parseInt(n.getParentNode().getAttributes().getNamedItem("cnumber").getNodeValue());
			int bnumber = Integer.parseInt(n.getParentNode().getParentNode().getAttributes().getNamedItem("bnumber").getNodeValue());
			captionList[i] = new CaptionImpl(text,bnumber,cnumber,vnumber);
		}		
		return captionList;	
	}
	
	private int[] readBooklist(final Document doc) throws SAXException, IOException, ParserConfigurationException {
		NodeList nodes = doc.getElementsByTagName("BIBLEBOOK");		
		int[] books = new int[nodes.getLength()];
		for (int i=0;i<nodes.getLength();i++) {			
			books[i] = Integer.parseInt(nodes.item(i).getAttributes().getNamedItem("bnumber").getNodeValue());			
		}
		return books;
	}
	@Override
	public final Position[] search(final String searchString) {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public final int[] getBookNumbers() {
		return books;
	}
	@Override
	public final BibleBook[] getBooks() {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public final BibleBook getBook(final int bnumber) {
		return new BibleBookImpl(bnumber, cache.getBook(bnumber));
	}
}
